﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Reflection;
using System.Diagnostics;
using System.Web.Configuration;
using System.Configuration;

namespace Lilium.Web.Mvc
{
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// Thread safety
	/// This type is thread safe.
	/// </remarks>
	public class EmbeededScriptResource: ScriptResource
	{
		static EmbeededScriptResource()
		{
			var section = (CompilationSection)WebConfigurationManager.GetSection("system.web/compilation");
			if (section == null)
				section = (CompilationSection)ConfigurationManager.GetSection("system.web/compilation");
			if (section != null)
				m_UseDebugVersion = section.Debug;
		}


		public EmbeededScriptResource(
			string name, Assembly resourceAssembly, string resourceName, string contentType, OutputCachePolicy cachePolicy)
			: base(name, contentType, cachePolicy)
		{
			if (string.IsNullOrEmpty(resourceName))
				throw new ArgumentNullOrEmptyException("resourceName");

			byte[] content;
			if (UseDebugVersion)
			{
				var indexOfLastDelimiter = resourceName.LastIndexOf('.');
				var debugResourceName = indexOfLastDelimiter != -1
					? resourceName.Substring(0, indexOfLastDelimiter) + ".debug" + resourceName.Substring(indexOfLastDelimiter)
					: resourceName + ".debug";
				if (!TryLoadResource(resourceAssembly, debugResourceName, out content)
					&& !TryLoadResource(resourceAssembly, resourceName, out content))
					throw new InvalidOperationException(string.Format(
						Resources.Culture,
						Resources.EmbeededScriptResource_EmbeededResourceNotFound_0resourceName_1assemblyName,
						resourceName, resourceAssembly.FullName));
			}
			else
				if (!TryLoadResource(resourceAssembly, resourceName, out content))
					throw new InvalidOperationException(string.Format(
						Resources.Culture,
						Resources.EmbeededScriptResource_EmbeededResourceNotFound_0resourceName_1assemblyName,
						resourceName, resourceAssembly.FullName));

			m_Content = content;
		}

		protected override void OnProcessRequest(ControllerContext context)
		{
			if (context == null)
				throw new ArgumentNullException("context");

			var response = context.HttpContext.Response;
			response.OutputStream.Write(Content, 0, Content.Length);
		}

		#region protected static bool UseDebugVersion

		private static readonly bool m_UseDebugVersion;

		protected static bool UseDebugVersion { [DebuggerNonUserCodeAttribute] get { return m_UseDebugVersion; } }

		#endregion

		private static bool TryLoadResource(Assembly resourceAssembly, string resourceName, out byte[] content)
		{
			if (resourceAssembly == null)
				throw new ArgumentNullException("resourceAssembly");

			using (var stream = resourceAssembly.GetManifestResourceStream(resourceName))
				if (stream == null)
				{
					content = null;
					return false;
				}
				else
				{
					content = new byte[stream.Length];
					stream.Read(content, 0, content.Length);
					return true;
				}
		}

		#region private byte[] Content

		private readonly byte[] m_Content;

		private byte[] Content { [DebuggerNonUserCodeAttribute] get { return m_Content; } }

		#endregion
	}
}